home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 May: Tool Chest / Developer CD Series Tool Chest (Apple Computer)(May 1999).iso / Tool Chest / Networking / SNMP / SNMP Development / MacSNMP Developer 1.0.2 / Sample Agent / Sources / SampleAgent.cp next >
Encoding:
Text File  |  1993-06-15  |  45.5 KB  |  1,308 lines  |  [TEXT/MPS ]

  1.  
  2. /*
  3.     File:        SampleAgent.cp
  4.  
  5.     Contains:    Sample Agent
  6.  
  7.     Copyright:    © 1992-1992 by Apple Computer, Inc., all rights reserved.
  8.  
  9. */
  10.  
  11. /***************************************************************************************
  12.  
  13.     This sample agent provides an example of how to build an SNMP agent for the
  14.     Macintosh. The SNMP Manager is a dynamically loaded shared library which runs under
  15.     the Macintosh Shared Library Manager (S.L.M.).  SNMP agents for the Macintosh
  16.     must likewise be contained in shared libraries and must be written in c++. 
  17.     
  18.     An agent can be pre-loaded automatically by the Shared Library Manager or it can be loaded 
  19.     on command by other code running either inside our outside of a shared library.  This sample 
  20.     can be setup for either mode, see the SampleAgent.exp file.  It can also be loaded
  21.     and unloaded by the SNMPAgentTool.
  22.         
  23.     This agent "manages" a few simple variables and tables for demonstration purposes.
  24.     Variables are registered with the SNMP Manager by means of variable objects. These
  25.     variable objects are subclasses of the abstract class TSNMPVar found in the file
  26.     SNMPVar.h.  The TSNMPVar class has member functions for getting and setting the variable
  27.     data.  There are two examples of variable objects used in this agent - direct
  28.     variables and indirect variables.  Direct variables are given a size and pointer to the
  29.     variable data, indirect variables are given addresses of get and set functions to be called
  30.     when a get or a set is requested.
  31.     
  32.     When a packet is received requesting a set or get, the SNMP Manager will do the
  33.     ASN.1 decoding.  It will make a get or set request to the owning agent for each
  34.     variable involved in the transaction.  It will then handle the encoding and packetizing
  35.     of the result.  If a getnext call is made, the SNMP Manager will determine which
  36.     variable needs to be retrieved and it will call the appropriate agent.  The only time
  37.     an agent will receive a getnext request is for a table element, in which case the
  38.     agent must either return the value of that variable from the next row in the table,
  39.     or return the end of column error.
  40.     
  41.     The SNMP Manager uses a three phase set when setting variables.  This is of primary
  42.     importance when creating new rows in a table.  There are actually four phases described
  43.     as follows:
  44.     
  45.         setAllocate:    Allocate any memory required.  Make sure there is space and if
  46.                         required, save information for consistency check phase.
  47.                         
  48.         setConsistency:    Check for consistency.  This may involve checking that other
  49.                         variables are also getting set with proper values.
  50.                         
  51.         setChange:        Perform the set and make it permanent.  This stage is not
  52.                         allowed to fail.  Error checks must be made and errors reported
  53.                         during one of the earlier phases.
  54.                         
  55.         setRevert:        Either the setAllocate or the setConsistency failed for some
  56.                         variable being set in this transaction.  Everything should be
  57.                         reverted to its previous state.
  58.     
  59. ***************************************************************************************/
  60.  
  61. #ifndef __TYPES__
  62. #include <Types.h>
  63. #endif
  64.  
  65. #ifndef __RESOURCES__
  66. #include <Resources.h>
  67. #endif
  68.  
  69. #ifndef __TOOLUTILS__
  70. #include <ToolUtils.h>
  71. #endif
  72.  
  73. #ifndef __String__
  74. #include <String.h>
  75. #endif 
  76.  
  77. #ifndef    __SNMP__
  78. #include "SNMP.h"
  79. #endif
  80.  
  81. #ifndef __TSNMP__
  82. #include "TSNMP.h"
  83. #endif
  84.  
  85. #ifndef __LIBRARYMANAGERUTILITIES__
  86. #include <LibraryManagerUtilities.h>
  87. #endif
  88.  
  89. #ifndef __LIBRARYMANAGER__
  90. #include <LibraryManager.h>
  91. #endif
  92.  
  93. #ifndef __LIBRARYMANAGERCLASSES__
  94. #include <LibraryManagerClasses.h>
  95. #endif
  96.  
  97. #ifndef __STRINGS__
  98. #include <Strings.h>
  99. #endif
  100.  
  101. #ifndef __SAMPLESNMPAGENT__
  102. #include "SampleAgent.h"
  103. #endif
  104.  
  105. #ifndef __SAMPLEVAR__
  106. #include "SampleVar.h"
  107. #endif
  108.  
  109. /**********************************************************************
  110.     Variables and Constants
  111. **********************************************************************/
  112. /*
  113.     Variable data
  114.  
  115.     The following variables represent the managed data that this sample agent
  116.     manages.  In a real world agent, these variables would be in the entity being
  117.     managed, e.g. a router or server.
  118. */
  119.  
  120. // storage for the direct variables
  121.  
  122. long    gDirIntRW         = 100;        // a direct read/write variable
  123.  
  124. // storage for the indirect variables
  125.  
  126. long    gIndIntRW        = 200;        // an indirect read/write variable
  127. long    gIndIntR        = 300;        // an indirect read only variable
  128.  
  129. /*
  130.     Table 1
  131.     This table contains an integer and a string.  This is a single index table where
  132.     the SNMP index for the table is not a column within the table.  The valid SNMP indexes for 
  133.     this table range from 1 to kT1MaxSize. There are three valid rows in the table to
  134.     start with.  The element T1Int determines whether or not a row is valid (exists).  If this
  135.     element contains zero, the row does not exist.  If zero is written into it for an
  136.     existing row, the row is in effect deleted.  Just for kicks, the T1Int element will
  137.     not allow its value to be greater than 1000.
  138.     The element T1Str can contain any string, and will be set to all zeros by default
  139.     if a new row is created (by setting T1Int to non-zero) without setting the T1Str field.
  140. */
  141.  
  142. const short        kT1MaxSize = 20;        // size of the array to hold the table data
  143. const short        kT1StrSize = 12;        // size of TStr element
  144. const short        kT1Elem_IDSize = 13;    // size of base object id for this table - used to
  145.                                         // retrieve the indexes off the object id
  146.  
  147. long    gT1Int[kT1MaxSize]     = {1000, 2000, 3000};
  148. char    gT1Str[kT1MaxSize][kT1StrSize]    = {"t1 String 1", "t1 String 2", "t1 String 3"};
  149.  
  150. long        gT1IntTemp;                        // temp field to hold T1Int value for consistency check during set
  151. Boolean        gT1IntSetFlag = false;            // set flag for T1Int
  152.  
  153. /*    Table 2
  154.     This table contains an integer, a string, 2 indexes, and a valid field.  This is a 2 index
  155.     table where the SNMP indexes are columns of the table.  The valid SNMP indexes for 
  156.     this table range from 1 to kT2_MaxSize1 for index 1 and 1 to kT2MaxSize2 for index 2.
  157.     There are nine valid rows in the table to start with.  The Valid field of the table
  158.     determines whether or not a row is valid (exists) and is used to create and delete
  159.     rows.
  160. */
  161.  
  162. const short        kT2MaxSize1 = 10;        // dimensions of the array which holds the table data
  163. const short        kT2MaxSize2 = 10;        
  164.  
  165. const short        kT2StrSize = 64;        // size of string element
  166. const short        kT2Elem_IDSize = 13;    // size of base object id for this table - used to
  167.                                         // retrieve the indexes off the object id
  168.  
  169. // constants for T2Valid field                                        
  170. const short        kInvalid = 0;
  171. const short        kValid = 1;
  172.  
  173. long    gT2Index1[kT2MaxSize1][kT2MaxSize2] = {    {1, 1, 1}, {2, 2, 2}, {3, 3, 3} };                                            
  174. long    gT2Index2[kT2MaxSize1][kT2MaxSize2] = {    {1, 2, 3}, {1, 2, 3}, {1, 2, 3} };
  175. char    gT2Str[kT2MaxSize1][kT2MaxSize2][kT2StrSize] =
  176.     {
  177.         {"t2 String 1 1", "t2 String 1 2", "t2 String 1 3"},
  178.         {"t2 String 2 1", "t2 String 2 2", "t2 String 2 3"},
  179.         {"t2 String 3 1", "t2 String 3 2", "t2 String 3 3"}
  180.     };
  181.             
  182. long    gT2Valid[kT2MaxSize1][kT2MaxSize2] =
  183.     {
  184.         {kValid, kValid, kValid},
  185.         {kValid, kValid, kValid},
  186.         {kValid, kValid, kValid}
  187.     };
  188.     
  189. // for consistency check
  190.  
  191. Boolean        gT2StrSetFlag = false;
  192. Boolean        gT2ValidSetFlag = false;
  193. long        gT2ValidTemp;                
  194.  
  195. /**********************************************************************
  196.     Local Function Prototypes
  197. **********************************************************************/
  198.  
  199. /*
  200.     Callback function prototypes
  201.     
  202.     These are the callback functions used by the indirect variables for getting and
  203.     setting the variable values.
  204. */
  205.         
  206. static OSErr
  207. GetIndIntRW(Boolean next, ObjectIDPtr id, Ptr bufPtr, Size bufSize, Size *bufUsed);
  208.  
  209. static OSErr 
  210. SetIndIntRW(ObjectIDPtr id, Ptr bufPtr, Size bufSize, SetStage action);
  211.  
  212. static OSErr
  213. GetIndIntR(Boolean next, ObjectIDPtr id, Ptr bufPtr, Size bufSize, Size *bufUsed);
  214.  
  215. static OSErr
  216. GetT1Int(Boolean next, ObjectIDPtr id, Ptr bufPtr, Size bufSize, Size *bufUsed);
  217.  
  218. static OSErr 
  219. SetT1Int(ObjectIDPtr id, Ptr bufPtr, Size bufSize, SetStage action);
  220.  
  221. static OSErr
  222. GetT1Str(Boolean next, ObjectIDPtr id, Ptr bufPtr, Size bufSize, Size *bufUsed);
  223.  
  224. static OSErr 
  225. SetT1Str(ObjectIDPtr id, Ptr bufPtr, Size bufSize, SetStage action);
  226.  
  227. static OSErr
  228. GetT2Index1(Boolean next, ObjectIDPtr id, Ptr bufPtr, Size bufSize, Size *bufUsed);
  229.  
  230. static OSErr
  231. GetT2Index2(Boolean next, ObjectIDPtr id, Ptr bufPtr, Size bufSize, Size *bufUsed);
  232.  
  233. static OSErr
  234. GetT2Str(Boolean next, ObjectIDPtr id, Ptr bufPtr, Size bufSize, Size *bufUsed);
  235.  
  236. static OSErr 
  237. SetT2Str(ObjectIDPtr id, Ptr bufPtr, Size bufSize, SetStage action);
  238.  
  239. static OSErr
  240. GetT2Valid(Boolean next, ObjectIDPtr id, Ptr bufPtr, Size bufSize, Size *bufUsed);
  241.  
  242. static OSErr 
  243. SetT2Valid(ObjectIDPtr id, Ptr bufPtr, Size bufSize, SetStage action);
  244.  
  245. // other local functions
  246.  
  247. void
  248. ClearCharArray(char    array[], unsigned short size);        
  249.     // clear a char array
  250.  
  251. OSErr
  252. FindT1Index(ObjectIDPtr id, Boolean next, Boolean forSet, unsigned short& theIndex);
  253.     // Find the correct index for the table 1 array - extracts it from the object id.
  254.     // Takes into account the setting of the next flag (getnext) and whether or not
  255.     // a set is being performed.
  256.     
  257. OSErr
  258. FindT2Index(ObjectIDPtr id, Boolean next, Boolean forSet, unsigned short& theIndex1, 
  259.         unsigned short& theIndex2);
  260.     // Find the correct indexes for the table 1 array - extracts it from the object id.
  261.     // Takes into account the setting of the next flag (getnext) and whether or not
  262.     // a set is being performed.
  263.  
  264.  
  265. /*
  266.      Callback Function and Variable Ptr Arrays
  267.      
  268.      These arrays contain pointers to the get and set callback functions, and for
  269.      direct variables, the address of the variable storage.  These arrays are used in
  270.      conjunction with the Variable description resource to register the variables.
  271.      The variable description resource contains all the information required to register
  272.      the variables except (of course) these addresses.  Each variable description
  273.      in the resource contains an index into one of these arrays.    
  274. */
  275.  
  276. // callback functions for get
  277.  
  278. GetVarProcPtr        getProcArray[] = {    GetIndIntRW,
  279.                                         GetIndIntR,
  280.                                         NULL,
  281.                                         GetT1Int,
  282.                                         GetT1Str,
  283.                                         NULL,
  284.                                         GetT2Index1,
  285.                                         GetT2Index2,
  286.                                         GetT2Str,
  287.                                         GetT2Valid
  288. };
  289.     
  290. // callback functions for set
  291.  
  292. SetVarProcPtr        setProcArray[] = {    SetIndIntRW,
  293.                                         NULL,
  294.                                         NULL,
  295.                                         SetT1Int,
  296.                                         SetT1Str,
  297.                                         NULL,
  298.                                         NULL,
  299.                                         NULL,
  300.                                         SetT2Str,
  301.                                         SetT2Valid
  302. }; 
  303.  
  304. // address of direct variables
  305.  
  306. void*        varPtrArray[] = {    &gDirIntRW
  307. };
  308.  
  309. /*******************************************************************************
  310.      Class Member Functions
  311.     
  312. *******************************************************************************/
  313.  
  314.  
  315. /*******************************************************************************
  316.     TSampleSNMPAgent Constructor
  317.     
  318.     This is where we construct ourselves and register both our agent and the
  319.     variables we manage.
  320. *******************************************************************************/
  321. TSampleSNMPAgent::TSampleSNMPAgent()
  322. {
  323.     OSErr            result = noErr;    // to hold result codes
  324.     Str255            nameStr;        // to hold strings retrieved from 'STR#' resource
  325.     Str32            agentName;        // var for getting agent name
  326.     unsigned short    i;
  327.     short            savedRefNum;    // saved refnum for the library file object (used in Preflight & Postflight)
  328.     Handle            varRsrcHandle;    // handle to hold the resource containing the variable data
  329.     Handle             nameRsrcHandle;    // handle to hold the name string list resource
  330.     TSampleSNMPAgent* anSNMPAgent;    // used to verify that the agent doesn't already exist
  331.     
  332.     fValid = false;                    // set valid to false to start
  333.                                     // this value is returned by the IsValid method
  334.                                     // so that the "creator" can determine if the constructor
  335.                                     // succedded or failed - since contructors cannot return
  336.                                     // a result.
  337.                                     
  338.     fRegistered=false;                // we have not registered this Agent yet
  339.     
  340.     if (!fSNMPManagerPtr)            // is the SNMP Manager there ?
  341.         return;        
  342.         
  343.     // Lookup this object type with the Arbitrator.    
  344.     // First get the pointer to the Arbitrator
  345.     
  346.     TArbitrator*    theArbitrator = GetGlobalArbitrator();        // get the global arbitrator
  347.     anSNMPAgent = (TSampleSNMPAgent*)theArbitrator->LookupObject(kTSampleSNMPAgentID);
  348.     if(anSNMPAgent) return;        // Already created
  349.     
  350.     // Now we must get our variable description resource to get the information we need
  351.     // to register our agent and variables.  To get any resource in our library file,
  352.     // we must first do a preflight to set it in the resource chain.  When we are done
  353.     // we must do a postflight on it to return things to their previous state.
  354.     
  355.     // First we must get our library file object
  356.     
  357.     fAgentLibraryPtr = GetLocalLibraryFile();
  358.     if(!fAgentLibraryPtr)             // is the library file there ?
  359.         return;
  360.     
  361.     // Then we preflight it - saving the old RefNum for the postflight
  362.     // when we're done.
  363.     
  364.     fAgentLibraryPtr->Preflight(savedRefNum);
  365.     
  366.     varRsrcHandle = Get1Resource(kVarRsrcType, kVarRsrcID);        // get our var description resource
  367.     if (!varRsrcHandle)                                            // did it succeed
  368.     {
  369.         fAgentLibraryPtr->Postflight(savedRefNum);        // do postflight
  370.         return;                                            // and get outa here !
  371.     }
  372.     
  373.     // Here we are going to lock the resource because we will have pointers pointing into it.
  374.     
  375.     HLock(varRsrcHandle);
  376.     
  377.     VarDescRsrcPtr        varResPtr = (VarDescRsrcPtr)(*varRsrcHandle);    // de-reference the handle
  378.     
  379.     // Now we get our names STR# resource which contains our agent name and the
  380.     // names of all our variables.
  381.     
  382.     nameRsrcHandle = Get1Resource('STR#', varResPtr->namesResID);        // get the names resource
  383.     if (!nameRsrcHandle)
  384.     {
  385.         ReleaseResource(varRsrcHandle);
  386.         fAgentLibraryPtr->Postflight(savedRefNum);        // do postflight
  387.         return;                                            // and get outa here !
  388.     }
  389.  
  390.     
  391.     // Get the agent name from the names resource using the index specified in the
  392.     // variable description resource.
  393.     
  394.     GetIndString(agentName, varResPtr->namesResID, varResPtr->agentStrIndex);
  395.     
  396.     // Now we call our Init member function, passing the name of the agent and the
  397.     // resource id and index for the description string.
  398.     
  399.     result = noErr;
  400.     
  401.     result = this->InitSNMPAgent(agentName, varResPtr->descResID, varResPtr->agentStrIndex, kOurVersion);
  402.     
  403.     if (!result)
  404.     {
  405.                 
  406.         // Now that we are all initializaed we need to Register this object 
  407.         // with the Arbitrator.    
  408.         // This registration should be done so that the Object can be found
  409.     
  410.         theArbitrator->RegisterObject(kTSampleSNMPAgentID, this);    // register ourself
  411.         fRegistered=true;                                            // we have now registered this Agent 
  412.  
  413.     
  414.         // We set our count to the field in the variable description resource
  415.         // which contains the count of the number of groups to register.  Then we will set
  416.         // our groupDataPtr to the first group data structure in the resource and begin
  417.         // registering the groups - counting down the count as we go.
  418.         
  419.         
  420.         short            *countPtr = &varResPtr->groupCount;                            // find the count
  421.         GroupRsrcPtr    groupDataPtr = (GroupRsrcPtr)(countPtr + 1);                // data for the first group
  422.         for (i = 0; i < *countPtr; i++)
  423.         {
  424.             GetIndString(nameStr, varResPtr->namesResID, groupDataPtr->strIndex);    // get the name
  425.             if (result = fSNMPManagerPtr->AddGroup(this, &groupDataPtr->objID, nameStr, varResPtr->descResID,
  426.                 groupDataPtr->strIndex))                                            // add the group
  427.                 break;
  428.             // now update the pointer to point to the next group in the resource
  429.             groupDataPtr = (GroupRsrcPtr)(&groupDataPtr->objID.id[0] + groupDataPtr->objID.count);    
  430.         }
  431.         
  432.         // Now register the variables.  We do essentially the same thing as with the groups.
  433.         // We also get the index from the resource and retrieve the address of the variable
  434.         // or the callback function from the appropriate array.
  435.         
  436.         if (!result)
  437.         {
  438.             TSampleIndirectVar        *theIndirectVar;
  439.             TSampleDirectVar        *theDirectVar;
  440.             
  441.             countPtr = (short*)groupDataPtr;                            // point to the variable count    
  442.             VarRsrcPtr        varDataPtr = (VarRsrcPtr)(countPtr + 1);    // point to the variable data
  443.             
  444.             for (i = 0; i < *countPtr; i++)
  445.             {
  446.                 GetIndString(nameStr, varResPtr->namesResID, varDataPtr->strIndex);            // get the var name
  447.                 if (varDataPtr->varType == 0)                                                // indirect variable?
  448.                 {
  449.                     if (!(theIndirectVar = new TSampleIndirectVar))                            // make the var
  450.                     {
  451.                         result = -1;
  452.                         break;
  453.                     }
  454.                     if (result = theIndirectVar->InitSampleIndirectVar(this, &varDataPtr->objID, kMyPrecedence, varDataPtr->type,
  455.                         varDataPtr->access, varResPtr->descResID, varDataPtr->strIndex,
  456.                         getProcArray[varDataPtr->ptrIndex], setProcArray[varDataPtr->ptrIndex]))
  457.                         break;
  458.                     if (result = fSNMPManagerPtr->AddMIBVar(theIndirectVar, nameStr))        // register it
  459.                         break;                                        
  460.                 } 
  461.                 else
  462.                 {
  463.                     if (!(theDirectVar = new TSampleDirectVar))                                    // make the var
  464.                     {
  465.                         result = -1;
  466.                         break;
  467.                     }
  468.                     if (result = theDirectVar->InitSampleDirectVar(this, &varDataPtr->objID, kMyPrecedence,
  469.                         varDataPtr->type, varDataPtr->access, varResPtr->descResID, varDataPtr->strIndex,
  470.                         varPtrArray[varDataPtr->ptrIndex], varDataPtr->dataSize))
  471.                         break;
  472.                     if (result = fSNMPManagerPtr->AddMIBVar(theDirectVar, nameStr))                // register it
  473.                         break;
  474.                 }
  475.         
  476.                 varDataPtr = (VarRsrcPtr)(&varDataPtr->objID.id[0] + varDataPtr->objID.count);    // update the rsrc data ptr
  477.             }
  478.         }
  479.     }
  480.     
  481.     // we're done - so finish up
  482.     
  483.     if (!result)
  484.         result = fSNMPManagerPtr->RegisterDone(this);    // we completed our registration
  485.     
  486.     ReleaseResource(nameRsrcHandle);            // release the names resource
  487.     ReleaseResource(varRsrcHandle);                // release the var resource
  488.     fAgentLibraryPtr->Postflight(savedRefNum);    // postflight the library
  489.     if (!result)                                // did we have a problem ?
  490.         fValid = true;                            // set the valid flag - we succeeded
  491. }
  492.  
  493. /*******************************************************************************
  494.     TSampleSNMPAgent Destructor
  495.     
  496.     Our destructor.  Called when we are deleted.
  497. *******************************************************************************/
  498. TSampleSNMPAgent::~TSampleSNMPAgent()
  499. {    
  500.     TArbitrator*    theArbitrator;
  501. //
  502. // remove yourself from the Arbitrator
  503. //
  504.     theArbitrator = GetGlobalArbitrator();        // get the global arbitrator
  505.     if(fRegistered == true) theArbitrator->UnregisterObject(kTSampleSNMPAgentID);
  506. }
  507.  
  508. /*******************************************************************************
  509.     TSampleSNMPAgent::IsValid
  510.     
  511.     Returns the validity state of the agent.  This provides a way for a creator
  512.     determine if the constructor succeeded or failed.
  513. *******************************************************************************/
  514.  
  515. Boolean TSampleSNMPAgent::IsValid() const
  516. {
  517.     return fValid;
  518. }
  519.  
  520.  
  521.  
  522. /*******************************************************************************
  523.     Constructor & Destructor for the Sample Direct Variable
  524. *******************************************************************************/
  525. TSampleDirectVar::TSampleDirectVar()
  526. {
  527. }
  528.  
  529. TSampleDirectVar::~TSampleDirectVar()
  530. {
  531. }
  532.  
  533. /*******************************************************************************
  534.      TSampleDirectVar::InitSNMPDirectVar
  535.     
  536.     Init for direct variables.  Direct variables objects keep a ptr to the
  537.     actual variable's address and a size.  The direct variable object's
  538.     member functions do the actual getting as setting.
  539. *******************************************************************************/
  540.  
  541. OSErr TSampleDirectVar::InitSampleDirectVar(
  542.                                 TSNMPAgent* agent,         // unique identifier for the agent
  543.                                 ObjectIDPtr id,         // unique identifier of the variable
  544.                                 short         precedence, // lowest value gets responsibility
  545.                                 ASNTagType    type,        // defines variable encoding
  546.                                 SMIAccess     access,             // read/write, read-only, or no access
  547.                                 short        descResID,            // resource id of description  STR# resource
  548.                                 short        descStrIndex,        // index of description string in STR# resource
  549.                                 void*        dataPtr,
  550.                                 short        dataSize)
  551. {
  552.     fDataPtr = (char*)dataPtr;                                // save the addr of the var storage
  553.     fDataSize = dataSize;                                    // save the variable size
  554.     return this->InitSNMPVar(agent, id, precedence, type, access, descResID, descStrIndex);    // init our superclass
  555.  
  556. }
  557.  
  558. /*******************************************************************************
  559.     TSampleDirectVar::GetVariable
  560.     
  561.     We do not have any tables which are handled as direct variables, so this
  562.     member function should never get called with get next.    
  563. *******************************************************************************/
  564.  
  565. OSErr TSampleDirectVar::GetVariable(Boolean next,ObjectIDPtr, VarBuf* retBuf)
  566. {
  567.     if (next) return snmpBadID;
  568.     
  569.     if (retBuf->maxlen < fDataSize)            // is the buffer big enough ?
  570.         return snmpBufTooSmall;
  571.  
  572.     for (short i = 0; i < fDataSize; i++)    // copy the variable data to the buffer
  573.         retBuf->buf[i] = fDataPtr[i];
  574.     retBuf->len = fDataSize;                // set the size being returned
  575.     return snmpNoError;
  576. }
  577.  
  578. /*******************************************************************************
  579.     TSampleDirectVar::SetVariable
  580.     
  581.     Set a direct variable.
  582. *******************************************************************************/
  583.  
  584. OSErr TSampleDirectVar::SetVariable(ObjectIDPtr, VarBuf* setBuf, SetStage action)
  585. {
  586.     
  587.     if (action == setAllocate)
  588.     {
  589.         if (setBuf->len > fDataSize)
  590.             return snmpBufTooSmall;
  591.     }
  592.     else if(action == setChange)        // only change it during the change phase of the set
  593.     {
  594.         ClearCharArray(fDataPtr, fDataSize);        // clear the variable storage first
  595.         for (short i = 0; i < setBuf->len; i++)        // move the data
  596.             fDataPtr[i] = setBuf->buf[i];
  597.     }
  598.     return snmpNoError;
  599. }
  600.  
  601.  
  602. /*******************************************************************************
  603.     Constructor & Destructor for the Sample Direct Variable
  604. *******************************************************************************/
  605. TSampleIndirectVar::TSampleIndirectVar()
  606. {
  607. }
  608.  
  609. TSampleIndirectVar::~TSampleIndirectVar()
  610. {
  611. }
  612.  
  613.  
  614. /*******************************************************************************
  615.     TSampleIndirectVar::InitSNMPIndirectVar
  616.     
  617.     Init an indirect var object.  Indirect vars use get and set callback
  618.     functions for getting and setting the variable values. 
  619. *******************************************************************************/
  620.  
  621. OSErr TSampleIndirectVar::InitSampleIndirectVar(
  622.                                 TSNMPAgent* agent,         // unique identifier for the agent
  623.                                 ObjectIDPtr id,         // unique identifier of the variable
  624.                                 short         precedence, // lowest value gets responsibility
  625.                                 ASNTagType    type,        // defines variable encoding
  626.                                 SMIAccess     access,         // read/write, read-only, or no access
  627.                                 short        descResID,        // resource id of description  STR# resource
  628.                                 short        descStrIndex,    // index of description string in STR# resource
  629.                                 GetVarProcPtr getProc,
  630.                                 SetVarProcPtr setProc)
  631. {
  632.     fGetProc = getProc;                                            // save the get and set function ptrs
  633.     fSetProc = setProc;
  634.     return this->InitSNMPVar(agent, id, precedence, type, access, descResID, descStrIndex);    // init the superclass
  635. }
  636.  
  637. /*******************************************************************************
  638.     TSampleIndirectVar::GetVariable
  639.     
  640.     Get the value of an indirect variable.  Just calls the get function
  641.     which this variable was initialized with.  The next parameter for the
  642.     get function is set to indicate that whether this is a get or a getnext call.
  643. *******************************************************************************/
  644.  
  645. OSErr TSampleIndirectVar::GetVariable(Boolean next,ObjectIDPtr theID, VarBuf* retBuf)
  646. {
  647.     if (fGetProc)
  648.         return fGetProc(next, theID, retBuf->buf, retBuf->maxlen, (Size *)&retBuf->len);
  649.     else
  650.         return snmpNoVarFound;
  651. }
  652.  
  653. /*******************************************************************************
  654.     TSampleIndirectVar::SetVariable
  655.     
  656.     Set the value of an indirect variable.  Just calls the get function
  657.     which this variable was initialized with.  
  658. *******************************************************************************/
  659.  
  660. OSErr TSampleIndirectVar::SetVariable(ObjectIDPtr theID, VarBuf* setBuf, SetStage action)
  661. {
  662.     if (fSetProc)
  663.         return fSetProc(theID, setBuf->buf, setBuf->len, action);
  664.     else
  665.         return snmpNoVarFound;
  666. }
  667.  
  668.  
  669. /*******************************************************************************
  670.     Callback Functions
  671.     
  672.     The callback functions for setting and getting the indirect variables.
  673. *******************************************************************************/
  674.  
  675. /*******************************************************************************
  676.     GetIndIntRW
  677.     
  678.     This callback function will be called by the SNMP Manager to get the value 
  679.     of the variable gIndIntRW.  We only need to make sure that the buffer is
  680.     big enough, and then return the value and size along with the result code.
  681. *******************************************************************************/
  682. static OSErr
  683. GetIndIntRW(Boolean /* next */, ObjectIDPtr /* id */, Ptr bufPtr, Size bufSize, Size *bufUsed) {
  684.  
  685.     long        *longPtr = (long*)bufPtr;    // used to copy response to buf
  686.     OSErr        result;
  687.  
  688.     *bufUsed = 0;                            // set in case of error
  689.     
  690.     if (bufSize < sizeof(long))             // buffer big enough ?
  691.         result = snmpBufTooSmall;            // too bad!
  692.     else
  693.     {
  694.         *longPtr = gIndIntRW;                // put value in buffer    
  695.         *bufUsed = sizeof(long);            // set the size used
  696.         result = snmpNoError;                
  697.     }
  698.     
  699.     return result;            
  700.  
  701. /*******************************************************************************
  702.     SetIndIntRW
  703.     
  704.     This callback function will be called by the SNMP Manager to set the value 
  705.     of the variable gIndIntRW.  We set the new value during the set stage of 
  706.     the three phase set.
  707.     For setting of integer values, the SNMP Manager will always pass longs
  708.     in the buffer, so there is not need for us to check the buffer size.
  709. *******************************************************************************/
  710. static OSErr 
  711. SetIndIntRW(ObjectIDPtr   , Ptr bufPtr, Size , SetStage action) {
  712.  
  713. #pragma xunused (id,bufSize);
  714.  
  715.     long        *longPtr = (long*)bufPtr;    // used to copy response to buf
  716.     OSErr        result = snmpNoError;        // result = no error unless otherwise changed
  717.  
  718.     if (action == setChange)                // change stage - set it
  719.         gIndIntRW = *longPtr;
  720.  
  721.     return result;            
  722. }
  723.  
  724.  
  725. /*******************************************************************************
  726.     GetIndIntR
  727.     
  728.     This functions is essentially the same as GetIndIntRW except that since this
  729.     is a read only variable - there is no corresponding set function.
  730. *******************************************************************************/
  731. static OSErr
  732. GetIndIntR(Boolean , ObjectIDPtr , Ptr bufPtr, Size bufSize, Size *bufUsed) {
  733.  
  734. #pragma xunused (next,id);
  735.  
  736.     long        *longPtr = (long*)bufPtr;    // used to copy response to buf
  737.     OSErr        result;
  738.  
  739.     *bufUsed = 0;                            // init in case of error
  740.     
  741.     if (bufSize < sizeof(long))             // buffer big enough ?
  742.         result = snmpBufTooSmall;    
  743.     else
  744.     {
  745.         *longPtr = gIndIntR;                // get the value    
  746.         *bufUsed = sizeof(long);            // set the size used
  747.         result = snmpNoError;    
  748.     }
  749.     
  750.     return result;            
  751. }
  752.  
  753.  
  754. /*******************************************************************************
  755.     GetT1Int
  756.     
  757.     Get the int element of table 1.  
  758. *******************************************************************************/
  759. static OSErr
  760. GetT1Int(Boolean next, ObjectIDPtr id, Ptr bufPtr, Size bufSize, Size *bufUsed) {
  761.  
  762.     long                *longPtr = (long*)bufPtr;    // used to copy response to buf
  763.     unsigned short        theIndex = 0;
  764.     OSErr                result;
  765.  
  766.     *bufUsed = 0;                            // init in case of error
  767.     
  768.     if (bufSize < sizeof(long))             // buffer big enough ?
  769.         result = snmpBufTooSmall;    
  770.     
  771.     // get the correct array index to use 
  772.     else if ((result = FindT1Index(id, next, false, theIndex)) == snmpNoError)
  773.     {
  774.         *longPtr = gT1Int[theIndex];            // move the value        
  775.         *bufUsed = sizeof(long);                // set the size used
  776.         
  777.         // Now set the returned object id correctly for the index that was used.
  778.         // This is only required when a getnext is performed.
  779.         // The field theIndex holds the index which was used for the array.
  780.         // The object id indexes for this table start with 1, while the array index
  781.         // is zero based - so we must add 1 to it.
  782.         if (next)
  783.         {
  784.             id->count = kT1Elem_IDSize + 1;            // set the count to the correct value
  785.                                                     // the base count plus 1 index
  786.             id->id[kT1Elem_IDSize] = theIndex + 1;    // set the index - it is 1 based
  787.         }
  788.         result = snmpNoError;
  789.     }
  790.     
  791.     return result;            
  792. }
  793.  
  794. /*******************************************************************************
  795.     SetT1Int
  796.     
  797.     Set the integer element of table 1. T1Int determines whether or not the
  798.     row in the table is exists.  If T1Int in the array is zero, the row is
  799.     treated as non-existent. Also just for kicks, we do not allow the value
  800.     of T1Int to be greater than 1000.  Adding and deleting rows is accomplished
  801.     by setting this element to the appropriate value.
  802.     When this element is being set, we set a flag to indicate it and we place
  803.     the value in a temp field so that if the other element of the table, T1Str,
  804.     is being set, it can do a consistency check to make sure the row either
  805.     exists and is not being deleted, or is being created. 
  806. *******************************************************************************/
  807. static OSErr
  808. SetT1Int(ObjectIDPtr id, Ptr bufPtr, Size , SetStage action) {
  809.  
  810. #pragma xunused (bufSize);
  811.  
  812.     long                *longPtr = (long*)bufPtr;    // used to copy response to buf
  813.     unsigned short        theIndex = 0;
  814.     OSErr                result = snmpNoError;
  815.     
  816.     // get the correct array index to use
  817.     if ((result = FindT1Index(id, false, true, theIndex)) == snmpNoError)
  818.     {
  819.         // first the allocate stage - Here we must allocate any memory needed
  820.         // or otherwise make sure there is space for the variable.
  821.         if (action == setAllocate)
  822.         {
  823.             if (*longPtr < 0 || *longPtr > 1000)    // check the value range
  824.                 result = snmpBadValue;
  825.             else
  826.             {
  827.                 gT1IntSetFlag = true;                // for consistency check by T1Str
  828.                 gT1IntTemp = *longPtr;                // save for consistency check by T1Str
  829.             }
  830.         }
  831.         else if (action == setChange)
  832.         {
  833.             gT1Int[theIndex] = gT1IntTemp;        // store the value
  834.             gT1IntSetFlag = false;                // clear the set flag
  835.             if (gT1IntTemp == 0)                // when deleting the row - set the default value for T1Str
  836.                 ClearCharArray(gT1Str[theIndex], kT1StrSize);
  837.         }
  838.         else if (action == setRevert)            // if we're reverting:
  839.             gT1IntSetFlag = 0;                    //   clear the set flag
  840.     }
  841.  
  842.     return result;            
  843. }
  844.  
  845. /*******************************************************************************
  846.     GetT1Str
  847.     
  848.     Get the String element from table 1.
  849. *******************************************************************************/
  850. static OSErr
  851. GetT1Str(Boolean next, ObjectIDPtr id, Ptr bufPtr, Size bufSize, Size *bufUsed) {
  852.  
  853.     unsigned short        theIndex;
  854.     OSErr                result;
  855.     char*                charPtr;
  856.     
  857.     *bufUsed = 0;                                // init in case of error
  858.     
  859.     if (bufSize < kT1StrSize)         // buffer big enough ?
  860.         result = snmpBufTooSmall;
  861.         
  862.     // get the correct array index to use
  863.     else if ((result = FindT1Index(id, next, false, theIndex)) == snmpNoError)
  864.     {
  865.         charPtr = gT1Str[theIndex];                // get the address of the correct array element
  866.  
  867.         for (short i = 0; i < kT1StrSize; i++)    // copy the data to the buffer
  868.             bufPtr[i] = charPtr[i];
  869.         *bufUsed = kT1StrSize;                    // set the bufUsed for return
  870.         
  871.         // Now set the returned object id correctly for the index that was used.
  872.         // This is only required when a getnext is performed.
  873.         // The field theIndex holds the index which was used for the array.
  874.         // The object id indexes for this table start with 1, while the array index
  875.         // is zero based - so we must add 1 to it.
  876.         if (next)
  877.         {
  878.             id->count = kT1Elem_IDSize + 1;            // set the count to the correct value
  879.                                                     // the base count plus 1 index
  880.             id->id[kT1Elem_IDSize] = theIndex + 1;    // set the index
  881.         }
  882.         result = snmpNoError;
  883.     }
  884.     
  885.     return result;            
  886. }
  887.  
  888. /*******************************************************************************
  889.     SetT1Str
  890.     
  891.     Set the string element of table 1.  We have to make sure it is only being
  892.     set for a valid (existing) row in the table or one that is being created
  893.     in this transaction.
  894. *******************************************************************************/
  895. static OSErr
  896. SetT1Str(ObjectIDPtr id, Ptr bufPtr, Size bufSize, SetStage action) {
  897.  
  898.     unsigned short        theIndex = 0;
  899.     OSErr                result = snmpNoError;
  900.  
  901.     
  902.     // get the correct array index to use
  903.     if ((result = FindT1Index(id, false, true, theIndex)) == snmpNoError)
  904.     {
  905.         // First the allocate stage - Here we must allocate any memory needed
  906.         // or otherwise make sure there is space for the variable.
  907.         if (action == setAllocate)
  908.         {
  909.             if (bufSize > kT1StrSize)        // buffer big enough ?
  910.                 result = snmpBadValue;
  911.         }
  912.         // During the consistency stage we must make sure we are setting this value
  913.         // in a row which either exists and is not being deleted, or one which is being
  914.         // created.
  915.         else if (action == setConsistency)
  916.         {
  917.             if ((gT1IntSetFlag && gT1IntTemp == 0) || (!gT1IntSetFlag && gT1Int[theIndex] == 0))
  918.                 result = snmpBadValue;
  919.         }
  920.         else if (action == setChange)
  921.         {
  922.             ClearCharArray(gT1Str[theIndex], kT1StrSize);        // clear any old value
  923.             for (short i = 0; i < bufSize; i++)                    // copy the data
  924.                 gT1Str[theIndex][i] = bufPtr[i];
  925.         }
  926.     }
  927.  
  928.     return result;            
  929. }
  930.  
  931.  
  932. /*******************************************************************************
  933.     GetT2Index1
  934.     
  935.     Get the index1 element from table 2.
  936. *******************************************************************************/
  937. static OSErr
  938. GetT2Index1(Boolean next, ObjectIDPtr id, Ptr bufPtr, Size bufSize, Size *bufUsed) {
  939.  
  940.     long                *longPtr = (long*)bufPtr;    // used to copy response to buf
  941.     unsigned short        theIndex1;
  942.     unsigned short        theIndex2;
  943.     OSErr                result;
  944.  
  945.     *bufUsed = 0;                            // init in case of error
  946.     
  947.     if (bufSize < sizeof(long))             // buffer big enough ?
  948.         result = snmpBufTooSmall;    
  949.             
  950.     // get the correct array indexes to use
  951.     else if ((result = FindT2Index(id, next, false, theIndex1, theIndex2)) == snmpNoError) {
  952.         *longPtr = gT2Index1[theIndex1][theIndex2];        // get the value
  953.         *bufUsed = sizeof(long);                        // set the buffer size used
  954.         
  955.         // Now set the returned object id correctly for the indexes that were used.
  956.         // This is only required when a getnext is performed.
  957.         // The index fields hold the index values which were used for the array.
  958.         // The object id indexes for this table start with 1, while the array indexes
  959.         // are zero based - so we must add 1 to them.
  960.         if (next)
  961.         {
  962.             id->count = kT2Elem_IDSize + 2;                    // set the count
  963.             id->id[kT2Elem_IDSize] = theIndex1 + 1;            // set the indexes - 1 based
  964.             id->id[kT2Elem_IDSize + 1] = theIndex2 + 1;
  965.         }
  966.         result = snmpNoError;
  967.     }
  968.     
  969.     return result;            
  970. }
  971.  
  972.  
  973. /*******************************************************************************
  974.     GetT2Index2
  975.     
  976.     Get the index2 element from table 2.
  977. *******************************************************************************/
  978. static OSErr
  979. GetT2Index2(Boolean next, ObjectIDPtr id, Ptr bufPtr, Size bufSize, Size *bufUsed) {
  980.  
  981.     long                *longPtr = (long*)bufPtr;    // used to copy response to buf
  982.     unsigned short        theIndex1;
  983.     unsigned short        theIndex2;
  984.     OSErr                result;
  985.  
  986.     *bufUsed = 0;                            // init in case of error
  987.     
  988.     if (bufSize < sizeof(long))             // buffer big enough ?
  989.         result = snmpBufTooSmall;    
  990.             
  991.     // get the correct array indexes to use
  992.     else if ((result = FindT2Index(id, next, false, theIndex1, theIndex2)) == snmpNoError) {
  993.         *longPtr = gT2Index2[theIndex1][theIndex2];        // get the value
  994.         *bufUsed = sizeof(long);                            // set the buffer size used
  995.         
  996.         // Now set the returned object id correctly for the indexes that were used.
  997.         // This is only required when a getnext is performed.
  998.         // The index fields hold the index values which were used for the array.
  999.         // The object id indexes for this table start with 1, while the array indexes
  1000.         // are zero based - so we must add 1 to them.
  1001.         if (next)
  1002.         {
  1003.             id->count = kT2Elem_IDSize + 2;                    // set the count
  1004.             id->id[kT2Elem_IDSize] = theIndex1 + 1;            // set the indexes - 1 based
  1005.             id->id[kT2Elem_IDSize + 1] = theIndex2 + 1;
  1006.         }
  1007.         result = snmpNoError;
  1008.     }
  1009.     
  1010.     return result;            
  1011. }
  1012.  
  1013. /*******************************************************************************
  1014.     GetT2Str
  1015.     
  1016.     Get the string element from table 2.
  1017. *******************************************************************************/
  1018. static OSErr
  1019. GetT2Str(Boolean next, ObjectIDPtr id, Ptr bufPtr, Size bufSize, Size *bufUsed) {
  1020.  
  1021.     unsigned short        theIndex1=0;
  1022.     unsigned short        theIndex2=0;
  1023.     OSErr                result;
  1024.     char*                strPtr;
  1025.  
  1026.     strPtr = gT2Str[theIndex1][theIndex2];
  1027.     
  1028.     *bufUsed = 0;                                // init in case of error
  1029.         
  1030.     // get the correct array indexes to use - depending on whether or not
  1031.     // next was set 
  1032.     if ((result = FindT2Index(id, next, false, theIndex1, theIndex2)) == snmpNoError)
  1033.     {
  1034.         strPtr = gT2Str[theIndex1][theIndex2];        // get ptr to the string
  1035.  
  1036.         if (bufSize < kT2StrSize)                     // buffer big enough ?
  1037.             result = snmpBufTooSmall;    
  1038.         else
  1039.         {
  1040.             for (short i = 0; i < kT2StrSize; i++)        // copy the string
  1041.                 bufPtr[i] = strPtr[i];
  1042.             *bufUsed = kT2StrSize;                // set the size used
  1043.             
  1044.             // now set the returned object id correctly for the indexes that were retrieved.
  1045.             // the object id indexes for this table start with 1 not 0 - so the
  1046.             // index values must be incremented by 1
  1047.             if (next)
  1048.             {
  1049.                 id->count = kT2Elem_IDSize + 2;                // set the count
  1050.                 id->id[kT2Elem_IDSize] = theIndex1 + 1;        // set the indexes - 1 based
  1051.                 id->id[kT2Elem_IDSize + 1] = theIndex2 + 1;
  1052.             }
  1053.             result = snmpNoError;    
  1054.         }
  1055.     }
  1056.     
  1057.     return result;            
  1058. }
  1059.  
  1060. /*******************************************************************************
  1061.     SetT2Str
  1062.     
  1063.     Set the string element of table 2. 
  1064. *******************************************************************************/
  1065. static OSErr
  1066. SetT2Str(ObjectIDPtr id, Ptr bufPtr, Size bufSize, SetStage action) {
  1067.  
  1068.     unsigned short        theIndex1 = 0;
  1069.     unsigned short        theIndex2 = 0;
  1070.     OSErr                result = snmpNoError;
  1071.  
  1072.     
  1073.     // get the correct array index to use
  1074.     if ((result = FindT2Index(id, false, true, theIndex1, theIndex2)) == snmpNoError)
  1075.     {
  1076.         // First the allocate stage - Here we must allocate any memory needed
  1077.         // or otherwise make sure there is space for the variable.
  1078.         if (action == setAllocate)
  1079.         {
  1080.             if (bufSize > kT2StrSize)
  1081.                 result = snmpBadValue;
  1082.         }
  1083.         else if (action == setConsistency)
  1084.         {
  1085.             if (    (gT2ValidSetFlag && gT2ValidTemp == kInvalid) || 
  1086.                     (!gT2ValidSetFlag && gT2Valid[theIndex1][theIndex2] == kInvalid)    )
  1087.                 result = snmpBadValue;
  1088.         }
  1089.         else if (action == setChange)
  1090.         {
  1091.             ClearCharArray(gT2Str[theIndex1][theIndex2], kT2StrSize);
  1092.             for (short i = 0; i < bufSize; i++)
  1093.                 gT2Str[theIndex1][theIndex2][i] = bufPtr[i];
  1094.         }                    
  1095.     }
  1096.  
  1097.     return result;            
  1098. }
  1099.  
  1100.  
  1101. /*******************************************************************************
  1102.     GetT2Valid
  1103.     
  1104.     Get the Valid element of table 2.  This element determines if the row 
  1105.     is valid (exists).
  1106. *******************************************************************************/
  1107. static OSErr
  1108. GetT2Valid(Boolean next, ObjectIDPtr id, Ptr bufPtr, Size bufSize, Size *bufUsed) {
  1109.  
  1110.     long                *longPtr = (long*)bufPtr;    // used to copy response to buf
  1111.     unsigned short        theIndex1;
  1112.     unsigned short        theIndex2;
  1113.     OSErr                result;
  1114.  
  1115.     *bufUsed = 0;                            // init in case of error
  1116.     
  1117.     if (bufSize < sizeof(long))             // buffer big enough ?
  1118.         result = snmpBufTooSmall;    
  1119.             
  1120.     // get the correct array indexes to use - depending on whether or not
  1121.     // next was set 
  1122.     else if ((result = FindT2Index(id, next, false, theIndex1, theIndex2)) == snmpNoError) {
  1123.         *longPtr = gT2Valid[theIndex1][theIndex2];        // get the value
  1124.         *bufUsed = sizeof(long);                        // set the buffer size used
  1125.         
  1126.         // Now set the returned object id correctly for the indexes that were used.
  1127.         // This is only required when a getnext is performed.
  1128.         // The index fields hold the index values which were used for the array.
  1129.         // The object id indexes for this table start with 1, while the array indexes
  1130.         // are zero based - so we must add 1 to them.
  1131.         if (next)
  1132.         {
  1133.             id->count = kT2Elem_IDSize + 2;                    // set the count
  1134.             id->id[kT2Elem_IDSize] = theIndex1 + 1;            // set the indexes - 1 based
  1135.             id->id[kT2Elem_IDSize + 1] = theIndex2 + 1;
  1136.         }
  1137.         result = snmpNoError;
  1138.     }
  1139.     
  1140.     return result;            
  1141. }
  1142.  
  1143. /*******************************************************************************
  1144.     SetT2Valid
  1145.     
  1146.     Set the Valid element of table 2. 
  1147. *******************************************************************************/
  1148. static OSErr
  1149. SetT2Valid(ObjectIDPtr id, Ptr bufPtr, Size bufSize, SetStage action) {
  1150.  
  1151.     long                *longPtr = (long*)bufPtr;
  1152.     unsigned short        theIndex1 = 0;
  1153.     unsigned short        theIndex2 = 0;
  1154.     OSErr                result = snmpNoError;
  1155.  
  1156.     
  1157.     // get the correct array index to use
  1158.     if ((result = FindT2Index(id, false, true, theIndex1, theIndex2)) == snmpNoError)
  1159.     {
  1160.         // First the allocate stage - Here we must allocate any memory needed
  1161.         // or otherwise make sure there is space for the variable.
  1162.         // We also set a flag and save the value being set so that if the T2Str element
  1163.         // of the table is being set, it can make a consistency check to be sure it is
  1164.         // being set in an existing row or in one that is being created.
  1165.         if (action == setAllocate)
  1166.             if (bufSize > sizeof(gT2Valid))
  1167.                 result = snmpBadValue;
  1168.             else
  1169.             {
  1170.                 gT2ValidSetFlag = true;
  1171.                 gT2ValidTemp = *longPtr;
  1172.             }
  1173.         else if (action == setChange)
  1174.         {
  1175.             if (gT2ValidTemp == kInvalid)                        // if deleting row - set default value for T2Str
  1176.                 ClearCharArray(gT2Str[theIndex1][theIndex2], kT2StrSize);
  1177.             gT2Valid[theIndex1][theIndex2] = gT2ValidTemp;        // set the value
  1178.             gT2Index1[theIndex1][theIndex2] = theIndex1 + 1;    // init/set the index1 element
  1179.             gT2Index2[theIndex1][theIndex2] = theIndex2 + 1;    // init/set the index2 element
  1180.             gT2ValidSetFlag = false;                            // clear the set flag
  1181.         }
  1182.         else if (action == setRevert)                            // if we are reverting
  1183.             gT2ValidSetFlag = false;                            //  clear the set flag                        
  1184.     }
  1185.  
  1186.     return result;            
  1187. }
  1188.  
  1189. /*******************************************************************************
  1190.     ClearCharArray
  1191.     
  1192.     Clears a character array.  Used to clear the string elements of the tables
  1193.     before moving data into them, since there is no guarantee that the strings
  1194.     will end in a null character.  The string variables are just an array of
  1195.     bytes.  And since, when setting them, we only move the number of bytes
  1196.     specified in the set call, we have to make sure the remaining bytes are 
  1197.     cleared.
  1198. *******************************************************************************/
  1199.  
  1200. void
  1201. ClearCharArray(char    array[], unsigned short size)
  1202. {
  1203.     for (short i = 0; i < size; i++)
  1204.         array[i] = 0;
  1205. }
  1206.  
  1207.  
  1208. /*******************************************************************************
  1209.     FindT1Index
  1210.     
  1211.     Determine the correct array index to use for the table 1 array.  This
  1212.     determination is based on the object id passed and whether a get, getnext,
  1213.     or a set is being performed.  
  1214. *******************************************************************************/
  1215. OSErr
  1216. FindT1Index(ObjectIDPtr id, Boolean next, Boolean forSet, unsigned short& theIndex)
  1217. {
  1218.     if (next)
  1219.     {
  1220.         // First find the starting index value.
  1221.         // If the count is less than the base id count - no indexes were specified
  1222.         // so start with 0 - otherwise we use the given index as the starting
  1223.         // point.  We don't have to increment it to start with the next entry in the
  1224.         // array since the index is 1 based and the array is zero based.
  1225.         
  1226.         theIndex = (unsigned short)(id->count <= kT1Elem_IDSize ? 0 : id->id[kT1Elem_IDSize]);
  1227.             
  1228.         // Since we must be doing a get if the next parameter is set
  1229.         // we search for the next available value in the table.
  1230.         // If the starting index is out of bounds, this loop will do the right thing.
  1231.         
  1232.         for (theIndex = theIndex; theIndex < kT1MaxSize; theIndex++)
  1233.             if (gT1Int[theIndex])
  1234.                 return snmpNoError;
  1235.         return snmpEndOfColumn;
  1236.     }
  1237.     
  1238.     // since this is not a next request - we check to see if the index is valid.
  1239.     // if the forSet flag is set we don't check to see if it points to a valid
  1240.     // entry in the array since this is for a set operation
  1241.     else if (     (id->count != kT1Elem_IDSize + 1)         ||                     // id count correct ?
  1242.                 ((theIndex = (unsigned short)(id->id[kT1Elem_IDSize] - 1)) >= kT1MaxSize) ||    // index within range ?
  1243.                 (theIndex < 0) ||                            
  1244.                 (!forSet && !gT1Int[theIndex])    )                            // if not set - is it a valid row ?
  1245.             return snmpBadID;
  1246.         
  1247.     return snmpNoError;
  1248. }
  1249.  
  1250.  
  1251. /*******************************************************************************
  1252.     FindT2Index
  1253.     
  1254.     Determine the correct array indexes to use for the table 2 array.  This
  1255.     determination is based on the object id passed and whether a get, getnext,
  1256.     or a set is being performed.
  1257. *******************************************************************************/
  1258. OSErr
  1259. FindT2Index(ObjectIDPtr id, Boolean next, Boolean forSet,  unsigned short& theIndex1, 
  1260.         unsigned short& theIndex2)
  1261. {
  1262.     
  1263.     if (next)
  1264.     {
  1265.         // First find the starting index values.
  1266.         // If one or both of the indexes are missing from the id, the missing ones
  1267.         // are set to zero to start at the beginning of the array.  Since the
  1268.         // indexes on the object id's are 1 based, and the arrays are zero based,
  1269.         // the first index must be decremented by 1 and the second index used
  1270.         // as is to start with the next entry in the array.
  1271.         
  1272.         theIndex1 = (unsigned short)(id->count < kT2Elem_IDSize + 1 ? 0 : id->id[kT2Elem_IDSize] - 1);
  1273.         theIndex2 = (unsigned short)(id->count < kT2Elem_IDSize + 2 ? 0 : id->id[kT2Elem_IDSize + 1]);    // start with next
  1274.             
  1275.         // Since we must be doing a get if the next parameter is set
  1276.         // we search for the next available value in the table.
  1277.         // If either or both of the initial starting indexes were out of bounds
  1278.         // this while loop will do the right thing with it.
  1279.         
  1280.         while (theIndex1 < kT2MaxSize1)
  1281.         {
  1282.             while (theIndex2 < kT2MaxSize2)
  1283.             {
  1284.                 if (gT2Valid[theIndex1][theIndex2])
  1285.                     return snmpNoError;
  1286.                 theIndex2++;
  1287.             }
  1288.             theIndex2 = 0;
  1289.             theIndex1++;    
  1290.         }
  1291.                     
  1292.         return snmpEndOfColumn;
  1293.     }
  1294.     
  1295.     // since this is not a next request - we check to see if the index is valid.
  1296.     // if the forSet flag is set we don't check to see if it points to a valid row.
  1297.     else if (    (id->count != kT2Elem_IDSize + 2) ||                             // size correct ?
  1298.                 ((theIndex1 = (unsigned short)(id->id[kT2Elem_IDSize] - 1)) >= kT2MaxSize1) ||    // within bounds ?
  1299.                 (theIndex1 < 0) ||
  1300.                 ((theIndex2 = (unsigned short)(id->id[kT2Elem_IDSize + 1] - 1)) >= kT2MaxSize2) ||
  1301.                 (theIndex2 < 0) ||
  1302.                 (!forSet && !gT2Valid[theIndex1][theIndex2])    )                // if set - valid row ?
  1303.             return snmpBadID;
  1304.         
  1305.     return snmpNoError;
  1306. }
  1307.